#include "buffer.h"

// 构造函数初始化了buffer_（动态分配指定大小的缓冲区）、readPos_和writePos_为0
Buffer::Buffer(int initBuffSize) : buffer_(initBuffSize), readPos_(0), writePos_(0) {}

// 计算并返回当前可读字节数，即写指针与读指针之间的距离
size_t Buffer::ReadableBytes() const {
    return writePos_ - readPos_; 
}

// 计算并返回当前可写字节数，即缓冲区剩余未使用的容量
size_t Buffer::WritebleBytes() const {
    return buffer_.size() - writePos_;
}

// 返回可以从缓冲区头部预留的字节数，等于当前读指针的位置
size_t Buffer::PrependableBytes() const {
    return readPos_;
}

// 返回当前读指针指向的数据区域的首地址，用于读取而不移动读指针
const char* Buffer::Peek() const {
    return BeginPtr_() + readPos_;
}

// 移动读指针 readPos_ 向后 len 字节，表示已经读取了 len 字节
void Buffer::Retrive(size_t len) {
    assert(len <= ReadableBytes());
    readPos_ += len;
}

// 移动读指针到 end 指向的位置
void Buffer::RetriveUntil(const char* end) {
    assert(Peek() <= end);
    Retrive(end - Peek());
}
// 清空缓冲区，将读写指针都置为0，并清空缓冲区内容
void Buffer::RetriveAll()
{
    bzero(&buffer_[0], buffer_.size());
    readPos_ = writePos_ = 0;
}

// 将当前可读数据转化为字符串并返回，然后执行 RetriveAll()
std::string Buffer::RetriveAllToStr() {
    std::string str(Peek(), ReadableBytes());
    RetriveAll();
    return str;
}

std::string Buffer::RetriveAllToStrConst() const{
    std::string str(Peek(), ReadableBytes());
    return str;
}

// 返回当前可写位置的常量指针
const char* Buffer::BeginWriteConst() const {
    return BeginPtr_() + writePos_;
}

// 返回当前可写位置的非常量指针
char* Buffer::BeginWrite() {
    return BeginPtr_() + writePos_;
}

// 标记已写入 len 字节的数据，向前移动写指针
void Buffer::HasWritten(size_t len) {
    writePos_ += len;
}

// Append 系列函数将不同来源的数据追加到缓冲区，包括字符串、原始字节数据和另一个 Buffer 对象的数据
void Buffer::Append(const std::string& str) {
    Append(str.data(), str.length());
}

void Buffer::Append(const void* data, size_t len) {
    assert(data);
    Append(static_cast<const char*>(data), len);
}

// 添加str到缓冲区
void Buffer::Append(const char* str, size_t len) {
    assert(str);
    EnsureWriteable(len);
    std::copy(str, str + len, BeginWrite());
    HasWritten(len);
}

// 将buff中没读完的数据添加到buffer中
void Buffer::Append(const Buffer& buff) {
    Append(buff.Peek(), buff.ReadableBytes());
}

// 确保缓冲区有足够的可写空间，如果不够则扩展缓冲区
void Buffer::EnsureWriteable(size_t len) {
    if(WritebleBytes() < len)
    {
        MakeSpace_(len);
    }
    assert(WritebleBytes() >= len);
}

// 从给定的文件描述符 fd 读取数据，利用 readv() 函数尝试一次性读取尽可能多的数据，读取的内容会追加到缓冲区
ssize_t Buffer::ReadFd(int fd, int* saveErrno) {
    char buff[65535];       // 临时的数组，保证能够把所有的数据都读出来
    struct iovec iov[2];    // 原始数组
    const size_t writable = WritebleBytes();    // 记录下能写的空间

    // 分散读，保证数据全部读完
    iov[0].iov_base = BeginPtr_() + writePos_;
    iov[0].iov_len = writable;
    iov[1].iov_base = buff;
    iov[1].iov_len = sizeof(buff);

    const ssize_t len = readv(fd, iov, 2);      // 减少系统调用次数
    if(len < 0) {
        *saveErrno = errno;
    } else if(static_cast<size_t>(len) <= writable) {
        writePos_ += len;
    } else {
        writePos_ = buffer_.size();
        Append(buff, len - writable);
    }
    return len;
}

// 从缓冲区中读取数据并写入给定的文件描述符 fd
ssize_t Buffer::WriteFd(int fd, int* saveErrno) {
    size_t readSize = ReadableBytes();
    ssize_t len = write(fd, Peek(), readSize);
    if(len < 0) {
        *saveErrno = errno;
        return len;
    }
    readPos_ += len;
    return len;
}

// 返回缓冲区开始处的指针
char* Buffer::BeginPtr_() {
    return &*buffer_.begin();
}

// 返回缓冲区开始处的指针
const char* Buffer::BeginPtr_() const {
    return &*buffer_.begin();
}

// 扩展缓冲区，确保有 len 字节的连续可写空间。
// 如果空间不足，且无法通过预留空间解决，则直接扩容，同时可能需要重新排列现有数据以保持读写指针的有效性。
void Buffer::MakeSpace_(size_t len) {
    if(WritebleBytes() + PrependableBytes() < len) {
        buffer_.resize(writePos_ + len + 1);
    } else {
        size_t readable = ReadableBytes();
        std::copy(BeginPtr_() + readPos_, BeginPtr_() + writePos_, BeginPtr_());
        readPos_ = 0;
        writePos_ = readPos_ + readable;
        assert(readable == ReadableBytes());  //下标移动的正确性
    }
}